package com.fhyc.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fhyc.dao.*;
import com.fhyc.entity.*;
import com.fhyc.service.FileService;
import com.fhyc.service.SoInBusLoadForecastService;
import com.fhyc.service.SoInLoadForecastService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.BiFunction;

@Slf4j
@Service
public class FileServiceImpl implements FileService {

    public static String MX_URL;

    @Value("${file.python_MX}")
    private void setMxUrl(String url) {
        MX_URL = url;
    }

    public static String TD_URL;

    @Value("${file.python_TD}")
    private void setTdUrl(String url) {
        TD_URL = url;
    }

    @Resource
    private SoInBusLoadForecastDao soInBusLoadForecastDao;

    @Resource
    private SoInBusLoadForecastService soInBusLoadForecastService;

    @Autowired
    private SoInLoadForecastService soInLoadForecastService;

    @Resource
    private SoInBaseBusDao soInBaseBusDao;

    @Resource
    private SoInLfHis96lcDao slfHis96lcDao;

    @Resource
    private SoInLfForecast96lcDao soInLfForecast96lcDao;

    @Resource
    private SoInQxjCountryWeatherDao soInQXjCountryWeatherDao;

    @Resource
    private SoInFhLoadForecastDao soInFhLoadForecastDao;

    @Override
    public void addLfForecast96lcMX(String NETID, String ymd, Integer qxjzh) {

        QueryWrapper<SoInBaseBus> wrapper = new QueryWrapper<>();
        wrapper.eq("REAL_NETID", NETID);
        List<SoInBaseBus> soInBaseBuses = soInBaseBusDao.selectList(wrapper);
        if (!CollectionUtils.isEmpty(soInBaseBuses)) {
            for (SoInBaseBus soInBaseBus : soInBaseBuses) {
                Integer busid = soInBaseBus.getBusid();

                // 发送 POST 请求
                RestTemplate restTemplate = new RestTemplate();
                // 设置请求头
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                // 创建请求体
                Map<String, Object> content = new HashMap<>();
                //content.put("fh", new HashMap<>());
                //content.put("qw", new HashMap<>());
                //content.put("xdsd", new HashMap<>());
                //content.put("jsl", new HashMap<>());

                String year = ymd.substring(0, 4);
                String month = ymd.substring(4, 6);
                String day = ymd.substring(6, 8);

                String startDate = year + "-" + month + "-" + day + " 00:00:00";
                String endDate = year + "-" + month + "-" + day + " 23:59:59";

                // 获取母线历史负荷数据
                QueryWrapper<SoInLfHis96lc> lfHis96lcQueryWrapper = new QueryWrapper<>();
                lfHis96lcQueryWrapper.eq("YMD", ymd);
                lfHis96lcQueryWrapper.eq("BUSID", busid);
                SoInLfHis96lc his96lc = slfHis96lcDao.selectOne(lfHis96lcQueryWrapper);

                // 构建 fh 数据
                if (his96lc != null) {
                    Map<String, Double> fhMap = new HashMap<>();
                    long baseTimestamp = LocalDate.parse(ymd, DateTimeFormatter.BASIC_ISO_DATE)
                            .atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();

                    List<Double> values = his96lc.getValueList();
                    for (int i = 0; i < values.size(); i++) {
                        String timeField = String.format("T%04d", i * 15);  // T0000, T0015, ..., T2345
                        Long timestamp = baseTimestamp + i * 15 * 60 * 1000L;
                        Double value = values.get(i);
                        if (value != null) {
                            fhMap.put(String.valueOf(timestamp), value);
                        }
                    }
                    content.put("fh", fhMap);
                }

                // 获取气象数据
                QueryWrapper<SoInQxjCountryWeather> weatherQueryWrapper = new QueryWrapper<>();
                weatherQueryWrapper.ge("zlsc", startDate);
                weatherQueryWrapper.le("zlsc", endDate);
                weatherQueryWrapper.eq("qxjzh", qxjzh);
                List<SoInQxjCountryWeather> weatherList = soInQXjCountryWeatherDao.selectList(weatherQueryWrapper);

                // 构建 qw/xdsd/jsl 数据
                Map<String, Double> qwMap = new HashMap<>();
                Map<String, Double> xdsdMap = new HashMap<>();
                Map<String, Double> jslMap = new HashMap<>();

                for (SoInQxjCountryWeather weather : weatherList) {
                    long timestamp = weather.getZlsc().getTime(); // zlsc 是 Date 类型
                    qwMap.put(String.valueOf(timestamp), weather.getQw());
                    xdsdMap.put(String.valueOf(timestamp), weather.getXdsd());
                    jslMap.put(String.valueOf(timestamp), weather.getXsjsl());
                }

                content.put("qw", qwMap);
                content.put("xdsd", xdsdMap);
                content.put("jsl", jslMap);


                Map<String, Object> inputData = new HashMap<>();
                inputData.put("busid", busid);
                inputData.put("content", content);

                log.info("传入母线模型参数：{}", inputData);

                Map<String, Object> requestBody = new HashMap<>();
                requestBody.put("input_data", inputData);
                // 将请求体转换成字符串形式
                String jsonBody = JSONObject.toJSONString(requestBody);
                // 创建HttpEntity,发送POST请求
                HttpEntity<String> requestEntity = new HttpEntity<>(jsonBody, headers);
                try {
                    log.info("--------------开始请求母线模型接口------------");
                    ResponseEntity<String> response = restTemplate.postForEntity(MX_URL, requestEntity, String.class);
                    // 序列化整个response为JSON字符串
                    ObjectMapper objectMapper2 = new ObjectMapper();

                    log.info("--------------开始解析母线模型接口返回数据------------");
                    String responseBody = objectMapper2.writeValueAsString(response);
                    log.info(responseBody);

                    //处理插入数据
                    //-------------------------------

                } catch (Exception e) {
                    log.error(e.toString());
                }
            }
        }

    }

    @Override
    public void testAddLfForecast96lcMX(String json) {
        try {
            int busid = 0;
            try {
                ObjectMapper object = new ObjectMapper();
                JsonNode rootNode = object.readTree(json);
                busid = rootNode.path("input_data").path("busid").asInt();
                log.info("提取到的 busid: {}", busid);
            } catch (IOException e) {
                log.error("busid解析失败:{}", e.getMessage());
            }
            // 发送 POST 请求
            RestTemplate restTemplate = new RestTemplate();
            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
/*        // 创建请求体
        Map<String, Object> content = new HashMap<>();

        // 构建 fh 数据
        Map<String, Double> fhMap = new HashMap<>();

        content.put("fh", fhMap);


        // 获取气象数据

        // 构建 qw/xdsd/jsl 数据
        Map<String, Double> qwMap = new HashMap<>();
        Map<String, Double> xdsdMap = new HashMap<>();
        Map<String, Double> jslMap = new HashMap<>();


        content.put("qw", qwMap);
        content.put("xdsd", xdsdMap);
        content.put("jsl", jslMap);


        Map<String, Object> inputData = new HashMap<>();
        inputData.put("busid", busid);
        inputData.put("content", content);

        log.info("传入母线模型参数：{}", inputData);

        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("input_data", inputData);
        // 将请求体转换成字符串形式
        String jsonBody = JSONObject.toJSONString(requestBody);*/
            // 创建HttpEntity,发送POST请求
            HttpEntity<String> requestEntity = new HttpEntity<>(json, headers);

            log.info("--------------开始请求母线模型接口------------");
            ResponseEntity<String> response = restTemplate.postForEntity(MX_URL, requestEntity, String.class);
            // 序列化整个response为JSON字符串
            ObjectMapper objectMapper = new ObjectMapper();

            log.info("--------------开始解析母线模型接口返回数据------------");
            //String responseBody = objectMapper2.writeValueAsString(response);
            //log.info(responseBody);
            String body = response.getBody();
            //log.info("body:{}", body);

            // 获取原始 data 字段的字符串值
            log.info("-------------- data 字段的字符串值------------");
            JsonNode root = objectMapper.readTree(body);
            String dataStr = root.path("data").asText();
            //log.info(" data 字段的字符串值: {}", dataStr);

            // 转换target
            log.info("-------------- target 字段的字符串值------------");
            JsonNode dataNode = objectMapper.readTree(dataStr);
            JsonNode targetNode = dataNode.path("target");
            //log.info("target 字段的字符串值:{}", targetNode.asText());

            /*//测试
            String json = "{\"target\": {\"freq\": \"15T\", \"data\": {\"fh\": {\"2025-06-22 00:00:00\": 50.22, \"2025-06-22 00:15:00\": 51.0}}}}";
*/

            // 获取数据部分
            if (targetNode.isTextual()) {
                targetNode = objectMapper.readTree(targetNode.asText());
            }
            JsonNode fhNode = targetNode.path("data").path("fh");
            log.info("输出fh数据:{}", fhNode); // 输出fh数据

            // 提取 fh 数据，保存
            Iterator<Map.Entry<String, JsonNode>> fields = fhNode.fields();

            SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            SimpleDateFormat timeFormat = new SimpleDateFormat("HHmm");
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");

            //Map<String, Double> timeToFieldMap = new HashMap<>();
/*        while (fields.hasNext()) {
            //添加删除逻辑

            Map.Entry<String, JsonNode> entry = fields.next();
            String timestamp = entry.getKey();   // 时间戳
            Double value = entry.getValue().asDouble();  // 数值
            // 将时间戳字符串转为 Date 对象
            Date date = inputFormat.parse(timestamp);
            // 提取小时和分钟，格式化为 "HHmm"
            String timeField = timeFormat.format(date);
            String s = dateFormat.format(date);
            String fieldName = "T" + timeField;

            Integer YMD = Integer.valueOf(s);
            // 将对应的值存入 Map
            timeToFieldMap.put(fieldName, value);
        }
        soInLfForecast96lc.setYmd(YMD);
        for (int i = 0; i < 96; i++) {
            // 生成时间点的字符串，例如 T0000, T0015, ..., T2345
            String timeField = String.format("T%04d", i * 15);  // 格式化为 T0000, T0015, ..., T2345

            // 判断时间字段是否在 Map 中存在并且值不为 null
            if (timeToFieldMap.containsKey(timeField) && timeToFieldMap.get(timeField) != null) {
                // 获取对应的值并设置到 forecast 对象的相应字段
                soInLfForecast96lc.getClass().getMethod("set" + timeField, timeToFieldMap.get(timeField).getClass())
                        .invoke(soInLfForecast96lc, timeToFieldMap.get(timeField));
            }
        }*/
            Map<Integer, Map<String, Double>> dateToTimeValueMap = new HashMap<>();

            while (fields.hasNext()) {
                //添加删除逻辑
                Map.Entry<String, JsonNode> entry = fields.next();
                String timestamp = entry.getKey();   // 时间戳
                Double value = entry.getValue().asDouble();  // 数值
                // 将时间戳字符串转为 Date 对象
                Date date = inputFormat.parse(timestamp);
                // 提取小时和分钟，格式化为 "HHmm"
                String timeField = timeFormat.format(date);
                String dateStr = dateFormat.format(date);
                String fieldName = "T" + timeField;

                Integer ymd = Integer.valueOf(dateStr);
                //根据日期分组
                dateToTimeValueMap.putIfAbsent(ymd, new HashMap<>());
                //储存时间点和值
                dateToTimeValueMap.get(ymd).put(fieldName, value);
            }
            //处理每一天数据
            for (Map.Entry<Integer, Map<String, Double>> entry : dateToTimeValueMap.entrySet()) {
                Integer ymd = entry.getKey();
                Map<String, Double> timeValue = entry.getValue();

                // 提取并解析fh数据
                //SoInBusLoadForecast busLoadForecast = new SoInBusLoadForecast();
                SoInLfForecast96lc soInLfForecast96lc = new SoInLfForecast96lc();
                // 获取当前时间
                LocalDateTime now = LocalDateTime.now();
                soInLfForecast96lc.setSjrq(Timestamp.valueOf(now));
                soInLfForecast96lc.setBusid(busid);
                soInLfForecast96lc.setYmd(ymd);

                for (int i = 0; i < 96; i++) {
                    // 生成时间点的字符串，例如 T0000, T0015, ..., T2345
                    String timeField = String.format("T%04d", i * 15);  // 格式化为 T0000, T0015, ..., T2345

                    // 判断时间字段是否在 Map 中存在并且值不为 null
                    if (timeValue.containsKey(timeField) && timeValue.get(timeField) != null) {
                        // 获取对应的值并设置到 forecast 对象的相应字段
                        soInLfForecast96lc.getClass().getMethod("set" + timeField, timeValue.get(timeField).getClass())
                                .invoke(soInLfForecast96lc, timeValue.get(timeField));
                    }
                }
                log.info("-----------------------插入数据----------------------");
                log.info(soInLfForecast96lc.toString());
                //先删除
                log.info("-----------------删除数据库------------");
                soInLfForecast96lcDao.delete(new QueryWrapper<SoInLfForecast96lc>().eq("busid", busid).eq("ymd", ymd));
                // 保存到数据库
                log.info("-----------------存数据库------------");
                soInLfForecast96lcDao.insert(soInLfForecast96lc);
            }
        } catch (Exception e) {
            log.error(e.toString());
        }
    }

    @Override
    public void testAddLfForecast96lcMX2(MultipartFile file) {
        try {
            int busid = 0;
            try {
                // 读取文件内容为字符串
                String fileContent = new String(file.getBytes(), StandardCharsets.UTF_8);
                // 使用 Jackson 解析 JSON
                ObjectMapper object = new ObjectMapper();
                JsonNode rootNode = object.readTree(fileContent);
                // 提取 busid
                busid = rootNode.path("input_data").path("busid").asInt();
                log.info("提取到的 busid: {}", busid);
            } catch (IOException e) {
                log.error("busid解析失败:{}", e.getMessage());
            }

            // 使用 RestTemplate 构造 multipart 请求
            MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();

            // 关键：构造 HttpEntity，包装文件数据
            HttpHeaders fileHeaders = new HttpHeaders();
            fileHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);

            // 把 MultipartFile 转成 FileSystemResource 临时文件（用于转发）
            Path tempFile = Files.createTempFile("upload-", file.getOriginalFilename());
            file.transferTo(tempFile.toFile());

            HttpEntity<FileSystemResource> fileEntity =
                    new HttpEntity<>(new FileSystemResource(tempFile.toFile()), fileHeaders);

            body.add("file", fileEntity); // 注意：参数名要和第三方接口要求一致

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);

            HttpEntity<MultiValueMap<String, Object>> requestEntity =
                    new HttpEntity<>(body, headers);

            // 发请求
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> response = restTemplate.postForEntity(MX_URL, requestEntity, String.class);

            // 删除临时文件
            Files.deleteIfExists(tempFile);

            // 序列化整个response为JSON字符串
            ObjectMapper objectMapper = new ObjectMapper();

            log.info("--------------开始解析母线模型接口返回数据------------");
            String dataBody = response.getBody();
            //log.info("dataBody:{}", dataBody);

            // 获取原始 data 字段的字符串值
            log.info("-------------- data 字段的字符串值------------");
            JsonNode root = objectMapper.readTree(dataBody);
            String dataStr = root.path("data").asText();
            //log.info(" data 字段的字符串值: {}", dataStr);

            // 转换target
            log.info("-------------- target 字段的字符串值------------");
            JsonNode dataNode = objectMapper.readTree(dataStr);
            JsonNode targetNode = dataNode.path("target");
            //log.info("target 字段的字符串值:{}", targetNode.asText());

            /*//测试
            String json = "{\"target\": {\"freq\": \"15T\", \"data\": {\"fh\": {\"2025-06-22 00:00:00\": 50.22, \"2025-06-22 00:15:00\": 51.0}}}}";
*/

            // 获取数据部分
            if (targetNode.isTextual()) {
                targetNode = objectMapper.readTree(targetNode.asText());
            }
            JsonNode fhNode = targetNode.path("data").path("fh");
            log.info("输出fh数据:{}", fhNode); // 输出fh数据

            // 提取 fh 数据，保存
            Iterator<Map.Entry<String, JsonNode>> fields = fhNode.fields();

            SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            SimpleDateFormat timeFormat = new SimpleDateFormat("HHmm");
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");

            //Map<String, Double> timeToFieldMap = new HashMap<>();

            Map<Integer, Map<String, Double>> dateToTimeValueMap = new HashMap<>();

            while (fields.hasNext()) {
                //添加删除逻辑
                Map.Entry<String, JsonNode> entry = fields.next();
                String timestamp = entry.getKey();   // 时间戳
                Double value = entry.getValue().asDouble();  // 数值
                // 将时间戳字符串转为 Date 对象
                Date date = inputFormat.parse(timestamp);
                // 提取小时和分钟，格式化为 "HHmm"
                String timeField = timeFormat.format(date);
                String dateStr = dateFormat.format(date);
                String fieldName = "T" + timeField;

                Integer ymd = Integer.valueOf(dateStr);
                //根据日期分组
                dateToTimeValueMap.putIfAbsent(ymd, new HashMap<>());
                //储存时间点和值
                dateToTimeValueMap.get(ymd).put(fieldName, value);
            }
            //处理每一天数据
            for (Map.Entry<Integer, Map<String, Double>> entry : dateToTimeValueMap.entrySet()) {
                Integer ymd = entry.getKey();
                Map<String, Double> timeValue = entry.getValue();

                // 提取并解析fh数据
                //SoInBusLoadForecast busLoadForecast = new SoInBusLoadForecast();
                SoInLfForecast96lc soInLfForecast96lc = new SoInLfForecast96lc();
                // 获取当前时间
                LocalDateTime now = LocalDateTime.now();
                soInLfForecast96lc.setSjrq(Timestamp.valueOf(now));
                soInLfForecast96lc.setBusid(busid);
                soInLfForecast96lc.setYmd(ymd);

                for (int i = 0; i < 96; i++) {
                    // 生成时间点的字符串，例如 T0000, T0015, ..., T2345
                    String timeField = String.format("T%04d", i * 15);  // 格式化为 T0000, T0015, ..., T2345

                    // 判断时间字段是否在 Map 中存在并且值不为 null
                    if (timeValue.containsKey(timeField) && timeValue.get(timeField) != null) {
                        // 获取对应的值并设置到 forecast 对象的相应字段
                        soInLfForecast96lc.getClass().getMethod("set" + timeField, Double.class)
                                .invoke(soInLfForecast96lc, timeValue.get(timeField));
                    }
                }
                log.info("-----------------------插入数据----------------------");
                log.info(soInLfForecast96lc.toString());
                //先删除
                log.info("-----------------删除数据库------------");
                soInLfForecast96lcDao.delete(new QueryWrapper<SoInLfForecast96lc>().eq("busid", busid).eq("ymd", ymd));
                // 保存到数据库
                log.info("-----------------存数据库------------");
                soInLfForecast96lcDao.insert(soInLfForecast96lc);
            }
        } catch (Exception e) {
            log.error(e.toString());
        }
    }

    @Override
    public void testAddLoadForecastHisTD(String body) {
        try {
            String qyidString = null;
            try {
                ObjectMapper object = new ObjectMapper();
                JsonNode rootNode = object.readTree(body);
                qyidString = rootNode.path("input_data").path("qyid").asText();
                log.info("提取到的 qyid: {}", qyidString);
            } catch (IOException e) {
                log.error("qyid解析失败:{}", e.getMessage());
            }
            // 发送 POST 请求
            RestTemplate restTemplate = new RestTemplate();
            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            HttpEntity<String> requestEntity = new HttpEntity<>(body, headers);
            // 发请求
            log.info("--------------开始请求母线模型接口------------");
            ResponseEntity<String> response = restTemplate.postForEntity(TD_URL, requestEntity, String.class);
            // 序列化整个response为JSON字符串
            ObjectMapper objectMapper = new ObjectMapper();

            log.info("--------------开始解析统调模型接口返回数据------------");
            String dataBody = response.getBody();
            log.info("dataBody:{}", dataBody);

            // 获取原始 data 字段的字符串值
            log.info("-------------- data 字段的字符串值------------");
            JsonNode root = objectMapper.readTree(dataBody);
            String dataStr = root.path("data").asText();
            //log.info(" data 字段的字符串值: {}", dataStr);

            // 转换target
            log.info("-------------- target 字段的字符串值------------");
            JsonNode dataNode = objectMapper.readTree(dataStr);
            JsonNode targetNode = dataNode.path("target");
            //log.info("target 字段的字符串值:{}", targetNode.asText());

            // 获取数据部分
            if (targetNode.isTextual()) {
                targetNode = objectMapper.readTree(targetNode.asText());
            }
            JsonNode fhNode = targetNode.path("data").path("fh");
            log.info("输出fh数据:{}", fhNode); // 输出fh数据

            // 获取当前时间
            LocalDateTime now = LocalDateTime.now();
            Timestamp currentTime = Timestamp.valueOf(now);

            // 提取 fh 数据，保存
            Iterator<Map.Entry<String, JsonNode>> fields = fhNode.fields();

            SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //SimpleDateFormat timeFormat = new SimpleDateFormat("HHmm");
            //SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
            //处理所有时间点数据
            while (fields.hasNext()) {
                Map.Entry<String, JsonNode> entry = fields.next();
                String timestamp = entry.getKey();   // 时间戳
                Double value = entry.getValue().asDouble();  // 数值
                // 将时间戳字符串转为 Date 对象
                Date date = inputFormat.parse(timestamp);

                SoInLoadForecast forecast = new SoInLoadForecast();
                forecast.setId(UUID.randomUUID().toString());
                forecast.setQyid(qyidString);
                forecast.setYccj("");
                forecast.setRkcj("");
                forecast.setYcrq(new Timestamp(date.getTime()));
                forecast.setSjrq(currentTime);
                forecast.setYcz(value);
                log.info("-----------------------每一条数据----------------------");
                log.info(forecast.toString());
                //先删除
                log.info("-----------------删除历史预测数据------------");
                soInFhLoadForecastDao.delete(new QueryWrapper<SoInLoadForecast>()
                        .eq("QYID", qyidString)
                        .eq("YCRQ", new Timestamp(date.getTime())));
                //存数据库
                log.info("-----------------存数据库------------");
                soInFhLoadForecastDao.insert(forecast);
            }
        } catch (Exception e) {
            log.error(e.toString());
        }
    }

    @Override
    public void testAddLoadForecastHisTD2(MultipartFile file) {
        try {
            String qyidString = null;
            try {
                // 读取文件内容为字符串
                String fileContent = new String(file.getBytes(), StandardCharsets.UTF_8);
                // 使用 Jackson 解析 JSON
                ObjectMapper object = new ObjectMapper();
                JsonNode rootNode = object.readTree(fileContent);
                // 提取 qyid
                Integer qyid = rootNode.path("input_data").path("qyid").asInt();
                qyidString = String.valueOf(qyid);
                log.info("提取到的 qyid: {}", qyidString);
            } catch (IOException e) {
                log.error("qyid解析失败:{}", e.getMessage());
            }

            // 使用 RestTemplate 构造 multipart 请求
            MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();

            // 关键：构造 HttpEntity，包装文件数据
            HttpHeaders fileHeaders = new HttpHeaders();
            fileHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);

            // 把 MultipartFile 转成 FileSystemResource 临时文件（用于转发）
            Path tempFile = Files.createTempFile("upload-", file.getOriginalFilename());
            file.transferTo(tempFile.toFile());

            HttpEntity<FileSystemResource> fileEntity =
                    new HttpEntity<>(new FileSystemResource(tempFile.toFile()), fileHeaders);

            body.add("file", fileEntity); // 注意：参数名要和第三方接口要求一致

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);

            HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);

            // 发请求釦
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> response = restTemplate.postForEntity(TD_URL, requestEntity, String.class);

            // 删除临时文件
            Files.deleteIfExists(tempFile);

            // 序列化整个response为JSON字符串
            ObjectMapper objectMapper = new ObjectMapper();

            log.info("--------------开始解析统调模型接口返回数据------------");
            String dataBody = response.getBody();
            log.info("dataBody:{}", dataBody);

            // 获取原始 data 字段的字符串值
            log.info("-------------- data 字段的字符串值------------");
            JsonNode root = objectMapper.readTree(dataBody);
            String dataStr = root.path("data").asText();
            //log.info(" data 字段的字符串值: {}", dataStr);

            // 转换target
            log.info("-------------- target 字段的字符串值------------");
            JsonNode dataNode = objectMapper.readTree(dataStr);
            JsonNode targetNode = dataNode.path("target");
            //log.info("target 字段的字符串值:{}", targetNode.asText());

            // 获取数据部分
            if (targetNode.isTextual()) {
                targetNode = objectMapper.readTree(targetNode.asText());
            }
            JsonNode fhNode = targetNode.path("data").path("fh");
            log.info("输出fh数据:{}", fhNode); // 输出fh数据

            // 获取当前时间
            LocalDateTime now = LocalDateTime.now();
            Timestamp currentTime = Timestamp.valueOf(now);

            // 提取 fh 数据，保存
            Iterator<Map.Entry<String, JsonNode>> fields = fhNode.fields();

            SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //SimpleDateFormat timeFormat = new SimpleDateFormat("HHmm");
            //SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
            //处理所有时间点数据
            while (fields.hasNext()) {
                Map.Entry<String, JsonNode> entry = fields.next();
                String timestamp = entry.getKey();   // 时间戳
                Double value = entry.getValue().asDouble();  // 数值
                // 将时间戳字符串转为 Date 对象
                Date date = inputFormat.parse(timestamp);

                SoInLoadForecast forecast = new SoInLoadForecast();
                forecast.setId(UUID.randomUUID().toString());
                forecast.setQyid(qyidString);
                forecast.setYccj("");
                forecast.setRkcj("");
                forecast.setYcrq(new Timestamp(date.getTime()));
                forecast.setSjrq(currentTime);
                forecast.setYcz(value);
                log.info("-----------------------每一条数据----------------------");
                log.info(forecast.toString());
                //先删除
                log.info("-----------------删除历史预测数据------------");
                soInFhLoadForecastDao.delete(new QueryWrapper<SoInLoadForecast>()
                        .eq("QYID", qyidString)
                        .eq("YCRQ", new Timestamp(date.getTime())));
                //存数据库
                log.info("-----------------存数据库------------");
                soInFhLoadForecastDao.insert(forecast);
            }
        } catch (Exception e) {
            log.error(e.toString());
        }
    }


    /*     *//**
     * 统调负荷文件分析
     *
     * @param csvPaths
     * @return 统调负荷文件分析
     * @param csvPaths
     * @return
     * @throws IOException
     * @throws ParseException
     *//*
    @Override
    public List<String> readFileTD(List<String> csvPaths) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode rootNode = mapper.createObjectNode();
        ObjectNode inputData = rootNode.putObject("input_data");

        // 设置"qyid" 值
        inputData.put("qyid", 440000);

        // 创建 "content" 对象
        ObjectNode contentNode = inputData.putObject("content");
        contentNode.set("qw", mapper.createObjectNode());
        contentNode.set("xdsd", mapper.createObjectNode());
        contentNode.set("jsl", mapper.createObjectNode());
        contentNode.set("solar", mapper.createObjectNode());
        contentNode.set("fh", mapper.createObjectNode());

        String csvPath1 = "";
        String csvPath2 = "";
        String csvPath3 = "";

        for (String path : csvPath) {
            if (path.contains("QXSJ")) {
                csvPath1 = path;
            }
            if (path.contains("TDHF")) {
                csvPath2 = path;
            }
            if (path.contains("FBSGFYC")) {
                csvPath3 = path;
            }
        }

        try (BufferedReader reader = Files.newBufferedReader(Paths.get(csvPath1))) {
            // 使用CSV格式
            CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withIgnoreHeaderCase().withTrim());
            boolean firstLine = true; // 标记是否是第一行
            String[] headers = null; // 存储表头
            for (CSVRecord record : csvParser) {
                // 读取表头
                if (firstLine) {
                    headers = new String[record.size()];
                    for (int i = 0; i < record.size(); i++) {
                        headers[i] = record.get(i); // 将表头存储在数组中
                    }
                    firstLine = false; // 设置为false以跳过后续的第一行
                    continue;
                }
                // 忽略第一列，从第二列开始读取
                String timestamp = null;
                Double qwValue = null;
                Double xdsdValue = null;
                Double xsjslValue = null;
                Long date = null;
                for (int i = 1; i < record.size(); i++) { // 从第一列（索引0）开始跳过
                    try {
                        if (headers[i].equals("zlsc")) {
                            timestamp = String.valueOf(record.get(i)); // 转换为时间戳
                            if (StringUtils.isNotEmpty(timestamp)) {
                                date = parseDateToTimestamp(timestamp);
                            }
                        }
                    } catch (ParseException e) {
                        System.err.println("日期解析失败: " + timestamp);
                        continue; // 跳过此行
                    }
                    if (headers[i].equals("zsqw")) {
                        //
                        String qw = record.get(i);
                        if (StringUtils.isNotEmpty(qw)) {
                            qwValue = Double.parseDouble(record.get(i));
                        } else {
                            qwValue = 0.0;
                        }
                    }
                    if (headers[i].equals("zsxdsd")) {
                        String xdsd = record.get(i);
                        if (StringUtils.isNotEmpty(xdsd)) {
                            xdsdValue = Double.parseDouble(record.get(i));
                        } else {
                            xdsdValue = 0.0;
                        }
                    }
                    if (headers[i].equals("zsjsl")) {
                        String xsjsl = record.get(i);
                        if (StringUtils.isNotEmpty(xsjsl)) {
                            xsjslValue = Double.parseDouble(record.get(i));
                        } else {
                            xsjslValue = 0.0;
                        }
                    }
                    if (String.valueOf(date) != "null") {
                        ((ObjectNode) contentNode.get("qw")).put(String.valueOf(date), qwValue);
                        ((ObjectNode) contentNode.get("xdsd")).put(String.valueOf(date), xdsdValue);
                        ((ObjectNode) contentNode.get("jsl")).put(String.valueOf(date), xsjslValue);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try (BufferedReader reader = Files.newBufferedReader(Paths.get(csvPath2))) {
            // 使用CSV格式
            CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withIgnoreHeaderCase().withTrim());
            boolean firstLine = true; // 标记是否是第一行
            String[] headers = null; // 存储表头
            for (CSVRecord record : csvParser) {
                // 读取表头
                if (firstLine) {
                    headers = new String[record.size()];
                    for (int i = 0; i < record.size(); i++) {
                        headers[i] = record.get(i); // 将表头存储在数组中
                    }
                    firstLine = false; // 设置为false以跳过后续的第一行
                    continue;
                }
                // 忽略第一列，从第二列开始读取
                String timestamp = null;
                Double fhValue = null;
                Long date = null;
                for (int i = 1; i < record.size(); i++) { // 从第一列（索引0）开始跳过
                    try {
                        if (headers[i].equals("fhsj")) {
                            timestamp = String.valueOf(record.get(i)); // 转换为时间戳
                            if (StringUtils.isNotEmpty(timestamp)) {
                                date = parseDateToTimestamp(timestamp);
                            }
                        }
                    } catch (ParseException e) {
                        System.err.println("日期解析失败: " + timestamp);
                        continue; // 跳过此行
                    }
                    if (headers[i].equals("fh")) {
                        //
                        String fh = record.get(i);
                        if (StringUtils.isNotEmpty(fh)) {
                            fhValue = Double.parseDouble(record.get(i));
                        } else {
                            fhValue = 0.0;
                        }
                    }
                    if (String.valueOf(date) != "null") {
                        ((ObjectNode) contentNode.get("fh")).put(String.valueOf(date), fhValue);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try (BufferedReader reader = Files.newBufferedReader(Paths.get(csvPath3))) {
            // 使用CSV格式
            CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withIgnoreHeaderCase().withTrim());
            boolean firstLine = true; // 标记是否是第一行
            String[] headers = null; // 存储表头
            for (CSVRecord record : csvParser) {
                // 读取表头
                if (firstLine) {
                    headers = new String[record.size()];
                    for (int i = 0; i < record.size(); i++) {
                        headers[i] = record.get(i); // 将表头存储在数组中
                    }
                    firstLine = false; // 设置为false以跳过后续的第一行
                    continue;
                }
                // 忽略第一列，从第二列开始读取
                String timestamp = null;
                Double totalValue = null;
                Long date = null;
                for (int i = 1; i < record.size(); i++) { // 从第一列（索引0）开始跳过
                    try {
                        if (headers[i].equals("ycrq")) {
                            timestamp = String.valueOf(record.get(i)); // 转换为时间戳
                            if (StringUtils.isNotEmpty(timestamp)) {
                                date = parseDateToTimestamp(timestamp);
                            }
                        }
                    } catch (ParseException e) {
                        System.err.println("日期解析失败: " + timestamp);
                        continue; // 跳过此行
                    }
                    if (headers[i].equals("total")) {
                        //
                        String total = record.get(i);
                        if (StringUtils.isNotEmpty(total)) {
                            totalValue = Double.parseDouble(record.get(i));
                        } else {
                            totalValue = 0.0;
                        }
                    }
                    if (String.valueOf(date) != "null") {
                        ((ObjectNode) contentNode.get("solar")).put(String.valueOf(date), totalValue);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 将生成的 JSON 对象转换为字符串并打印
        String jsonResult = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
        System.out.println(jsonResult);
        return jsonResult;
    }*/

    /**
     * 统调负荷文件分析
     *
     * @param csvPaths
     * @return
     * @throws IOException
     * @throws ParseException
     */
    @Override
    public List<String> readFileTD(List<String> csvPaths) throws IOException {
        // 1. 定位文件
        String qxsjPath = csvPaths.stream().filter(p -> p.contains("QXSJ")).findFirst()
                .orElseThrow(() -> new IllegalArgumentException("找不到 QXSJ 文件"));
        String tdhfPath = csvPaths.stream().filter(p -> p.contains("TDFH")).findFirst()
                .orElseThrow(() -> new IllegalArgumentException("找不到 TDFH 文件"));
        String fbsPath = csvPaths.stream().filter(p -> p.contains("FBSGFSJ")).findFirst()
                .orElseThrow(() -> new IllegalArgumentException("找不到 FBSGFSJ 文件"));

        ObjectMapper mapper = new ObjectMapper();

        // 每个 qyid 对应一个 content 节点，里面预建五个子项
        Map<String, ObjectNode> map = new HashMap<>();

        // 工具：获取或创建 contentNode
        BiFunction<String, ObjectMapper, ObjectNode> getContentNode = (qyid, om) -> {
            return map.computeIfAbsent(qyid, id -> {
                ObjectNode node = om.createObjectNode();
                node.set("qw", om.createObjectNode());
                node.set("xdsd", om.createObjectNode());
                node.set("jsl", om.createObjectNode());
                node.set("solar", om.createObjectNode());
                node.set("fh", om.createObjectNode());
                return node;
            });
        };

        // 2. 解析 QXSJ.csv → qw, xdsd, jsl

        try (BufferedReader br = Files.newBufferedReader(Paths.get(qxsjPath))) {
            String headerLine = br.readLine();
            String[] raw = headerLine.split(",", -1);
            String[] cleanHeaders = Arrays.stream(raw).map(String::trim).map(h -> h.isEmpty() ? "null" : h).toArray(String[]::new);

            CSVFormat format = CSVFormat.DEFAULT.withHeader(cleanHeaders).withSkipHeaderRecord().withIgnoreHeaderCase().withTrim();
            try (CSVParser parser = new CSVParser(br, format)) {
                for (CSVRecord rec : parser) {
                    //int qyid = Integer.parseInt(rec.get("qyid"));
                    String qyid = rec.get("qyid");
                    long ts = parseDateToTimestamp(rec.get("zlsc"));

                    ObjectNode content = getContentNode.apply(qyid, mapper);
                    //((ObjectNode) content.get("qw")).put(String.valueOf(ts), parseDoubleOrZero(rec.get("zsqw")));
                    ((ObjectNode) content.get("qw")).put(String.valueOf(ts), parseDoubleOrZero(rec.get("真实气温")));
                    //((ObjectNode) content.get("xdsd")).put(String.valueOf(ts), parseDoubleOrZero(rec.get("zsxdsd")));
                    ((ObjectNode) content.get("xdsd")).put(String.valueOf(ts), parseDoubleOrZero(rec.get("真实相对湿度")));
                    //((ObjectNode) content.get("jsl")).put(String.valueOf(ts), parseDoubleOrZero(rec.get("zsjsl")));
                    ((ObjectNode) content.get("jsl")).put(String.valueOf(ts), parseDoubleOrZero(rec.get("真实降水量")));
                }
            }
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        // 3. 解析 TDHF.csv → fh

        try (BufferedReader br = Files.newBufferedReader(Paths.get(tdhfPath))) {
            String headerLine = br.readLine();
            String[] raw = headerLine.split(",", -1);
            String[] cleanHeaders = Arrays.stream(raw).map(String::trim).map(h -> h.isEmpty() ? "null" : h).toArray(String[]::new);

            CSVFormat format = CSVFormat.DEFAULT.withHeader(cleanHeaders).withSkipHeaderRecord().withIgnoreHeaderCase().withTrim();
            try (CSVParser parser = new CSVParser(br, format)) {

                for (CSVRecord rec : parser) {
                    //int qyid = Integer.parseInt(rec.get("qyid"));
                    String qyid = rec.get("qyid");
                    long ts = parseDateToTimestamp(rec.get("fhsj"));

                    ObjectNode content = getContentNode.apply(qyid, mapper);
                    ((ObjectNode) content.get("fh")).put(String.valueOf(ts), parseDoubleOrZero(rec.get("fh")));
                }
            }
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        // 4. 解析 FBSGFYC.csv → solar

        try (BufferedReader br = Files.newBufferedReader(Paths.get(fbsPath))) {
            String headerLine = br.readLine();
            String[] raw = headerLine.split(",", -1);
            String[] cleanHeaders = Arrays.stream(raw).map(String::trim).map(h -> h.isEmpty() ? "null" : h).toArray(String[]::new);

            CSVFormat format = CSVFormat.DEFAULT.withHeader(cleanHeaders).withSkipHeaderRecord().withIgnoreHeaderCase().withTrim();
            try (CSVParser parser = new CSVParser(br, format)) {

                for (CSVRecord rec : parser) {
                    //int qyid = Integer.parseInt(rec.get("qyid"));
                    String qyid = rec.get("qyid");
                    long ts = parseDateToTimestamp(rec.get("ycrq"));

                    ObjectNode content = getContentNode.apply(qyid, mapper);
                    ((ObjectNode) content.get("solar")).put(String.valueOf(ts), parseDoubleOrZero(rec.get("total")));
                }
            }
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        // 5. 为每个 qyid 构建 JSON 字符串
        List<String> results = new ArrayList<>();
        for (Map.Entry<String, ObjectNode> e : map.entrySet()) {
            String qyid = e.getKey();
            ObjectNode content = e.getValue();

            ObjectNode root = mapper.createObjectNode();
            ObjectNode inputData = root.putObject("input_data");
            inputData.put("qyid", qyid);
            inputData.set("content", content);

            results.add(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root));
        }
        System.out.println(results);
        return results;
    }

/**
 * 母线负荷文件分析
 *
 * @param csvPaths
 * @return
 * @throws JsonProcessingException
 *//*
    @Override
    public String readFileMX(List<String> csvPaths) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode rootNode = mapper.createObjectNode();
        ObjectNode inputData = rootNode.putObject("input_data");
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();

        // 设置"qyid" 值
        inputData.put("busid", 5278);
        // 创建 "content" 对象
        ObjectNode contentNode = inputData.putObject("content");
        contentNode.set("qw", mapper.createObjectNode());
        contentNode.set("xdsd", mapper.createObjectNode());
        contentNode.set("jsl", mapper.createObjectNode());
        contentNode.set("fh", mapper.createObjectNode());

        String csvPath1 = "";
        String csvPath2 = "";

        for (String path : csvPath) {
            if (path.contains("QXSJ")) {
                csvPath1 = path;
            }
            if (path.contains("MXFH")) {
                csvPath2 = path;
            }
        }
        try (BufferedReader reader = Files.newBufferedReader(Paths.get(csvPath1))) {
            // 使用CSV格式
            CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withIgnoreHeaderCase().withTrim());
            boolean firstLine = true; // 标记是否是第一行
            String[] headers = null; // 存储表头
            for (CSVRecord record : csvParser) {
                // 读取表头
                if (firstLine) {
                    headers = new String[record.size()];
                    for (int i = 0; i < record.size(); i++) {
                        headers[i] = record.get(i); // 将表头存储在数组中
                    }
                    firstLine = false; // 设置为false以跳过后续的第一行
                    continue;
                }
                // 忽略第一列，从第二列开始读取
                String timestamp = null;
                Double qwValue = null;
                Double xdsdValue = null;
                Double xsjslValue = null;
                Long date = null;
                for (int i = 1; i < record.size(); i++) { // 从第一列（索引0）开始跳过
                    try {
                        if (headers[i].equals("zlsc")) {
                            timestamp = String.valueOf(record.get(i)); // 转换为时间戳
                            if (StringUtils.isNotEmpty(timestamp)) {
                                date = parseDateToTimestamp(timestamp);
                            }
                        }
                    } catch (ParseException e) {
                        System.err.println("日期解析失败: " + timestamp);
                        continue; // 跳过此行
                    }
                    if (headers[i].equals("qw")) {
                        //
                        String qw = record.get(i);
                        if (StringUtils.isNotEmpty(qw)) {
                            qwValue = Double.parseDouble(record.get(i));
                        } else {
                            qwValue = 0.0;
                        }
                    }
                    if (headers[i].equals("xdsd")) {
                        // xdsdValue = Double.parseDouble(record.get(i));
                        String xdsd = record.get(i);
                        if (StringUtils.isNotEmpty(xdsd)) {
                            xdsdValue = Double.parseDouble(record.get(i));
                        } else {
                            xdsdValue = 0.0;
                        }
                    }
                    if (headers[i].equals("xsjsl")) {
                        // xsjslValue = Double.parseDouble(record.get(i));
                        String xsjsl = record.get(i);
                        if (StringUtils.isNotEmpty(xsjsl)) {
                            xsjslValue = Double.parseDouble(record.get(i));
                        } else {
                            xsjslValue = 0.0;
                        }
                    }
                    if (String.valueOf(date) != "null") {
                        ((ObjectNode) contentNode.get("qw")).put(String.valueOf(date), qwValue);
                        ((ObjectNode) contentNode.get("xdsd")).put(String.valueOf(date), xdsdValue);
                        ((ObjectNode) contentNode.get("jsl")).put(String.valueOf(date), xsjslValue);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try (BufferedReader br = new BufferedReader(new FileReader(csvPath2))) {
            String line;
            String[] headers = br.readLine().split(","); // 读取表头

            // 找到 YMD 列的索引
            int ymdIndex = -1;
            for (int i = 0; i < headers.length; i++) {
                if (headers[i].equalsIgnoreCase("YMD")) {
                    ymdIndex = i;
                    break;
                }
            }

            // 逐行读取数据
            while ((line = br.readLine()) != null) {
                String[] values = line.split(",");
                String ymd = values[ymdIndex];  // 获取 YMD 列的值
                Map<String, Double> timeData = new HashMap<>();

                // 从第二列开始遍历数据，每列代表一个时间段
                for (int i = 5; i < headers.length - 5; i++) {
                    String timeKey = headers[i].substring(1); // 去掉 "T" 前缀
                    //log.info("timeKey:{}",timeKey);
                    //String timeString = ymd + " " + timeKey.substring(0, 2) + ":" + timeKey.substring(2);
                    //String timeString = ymd.substring(0, 4) + "/" + ymd.substring(4, 6) + "/" + ymd.substring(6, 8) + " " + timeKey.substring(0, 2) + ":" + timeKey.substring(2);
                    if (ymd.length() == 8) {
                        // 将 YMD 格式化为 "yyyy/MM/dd HH:mm" 格式，并指定时间部分为 "00:00"
                        String formattedDateTime = ymd.substring(0, 4) + "/" +
                                ymd.substring(4, 6) + "/" +
                                ymd.substring(6, 8) + " " + timeKey.substring(0, 2) + ":" + timeKey.substring(2, 4);
                        //System.out.println("==:"+formattedDateTime);
                        long date = parseDateToTimestamp(formattedDateTime);
                        //System.out.println(date);
                        Double value = Double.parseDouble(values[i]);
                        ((ObjectNode) contentNode.get("fh")).put(String.valueOf(date), value);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 将生成的 JSON 对象转换为字符串并打印
        String jsonResult = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
        System.out.println(jsonResult);
        return jsonResult;
    }*/

    /**
     * 母线负荷文件分析
     *
     * @param csvPaths
     * @return
     * @throws JsonProcessingException
     */
    @Override
    public List<String> readFileMX(List<String> csvPaths) throws JsonProcessingException {
        // --- 1. 找出两个 CSV 文件路径 ---
        String qxsjPath = csvPaths.stream().filter(p -> p.contains("QXSJ")).findFirst()
                .orElseThrow(() -> new IllegalArgumentException("找不到 QXSJ 文件"));
        String mxfhPath = csvPaths.stream().filter(p -> p.contains("MXFH")).findFirst()
                .orElseThrow(() -> new IllegalArgumentException("找不到 MXFH 文件"));

        ObjectMapper mapper = new ObjectMapper();

        // --- 2. 读取 QXSJ 数据共享 ---
        ObjectNode sharedContent = mapper.createObjectNode();
        sharedContent.putObject("qw");
        sharedContent.putObject("xdsd");
        sharedContent.putObject("jsl");

        try (BufferedReader br = Files.newBufferedReader(Paths.get(qxsjPath))) {
            String headerLine = br.readLine();
            String[] raw = headerLine.split(",", -1);
            String[] cleanHeaders = Arrays.stream(raw).map(String::trim).map(h -> h.isEmpty() ? "null" : h).toArray(String[]::new);

            CSVFormat format = CSVFormat.DEFAULT.withHeader(cleanHeaders).withSkipHeaderRecord().withIgnoreHeaderCase().withTrim();
            try (CSVParser parser = new CSVParser(br, format)) {
                for (CSVRecord rec : parser) {
                    long ts = 0;
                    if (StringUtils.isNotEmpty(rec.get("zlsc"))) {
                        ts = parseDateToTimestamp(rec.get("zlsc"));
                    }
                    double qwVal = parseDoubleOrZero(rec.get("qw"));
                    double xdsdVal = parseDoubleOrZero(rec.get("xdsd"));
                    double jslVal = parseDoubleOrZero(rec.get("xsjsl"));

                    sharedContent.with("qw").put(String.valueOf(ts), qwVal);
                    sharedContent.with("xdsd").put(String.valueOf(ts), xdsdVal);
                    sharedContent.with("jsl").put(String.valueOf(ts), jslVal);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("解析 QXSJ 文件失败", e);
        }

        // --- 3. 读取 MXFH 数据，按 busid 分组 ---
        Map<Integer, ObjectNode> busidToFhMap = new HashMap<>();
        try (BufferedReader br = Files.newBufferedReader(Paths.get(mxfhPath))) {
            String headerLine = br.readLine();
            if (headerLine == null) throw new IllegalStateException("MXFH 文件为空");

            String[] rawHeaders = headerLine.split(",", -1);
            String[] cleanHeaders = Arrays.stream(rawHeaders).map(String::trim).map(h -> h.isEmpty() ? "null" : h).toArray(String[]::new);

            CSVFormat format = CSVFormat.DEFAULT.withHeader(cleanHeaders).withSkipHeaderRecord().withIgnoreHeaderCase().withTrim();
            CSVParser parser = new CSVParser(br, format);
            Map<String, Integer> headerMap = parser.getHeaderMap();

            String busidHeader = headerMap.keySet().stream()
                    .filter(h -> h.equalsIgnoreCase("busid"))
                    .findFirst()
                    .orElseThrow(() -> new IllegalStateException("缺少 busid 列"));

            for (CSVRecord rec : parser) {
                int busid = Integer.parseInt(rec.get(busidHeader));
                String ymd = rec.get("YMD");

                ObjectNode fhNode = busidToFhMap.computeIfAbsent(busid, k -> mapper.createObjectNode());

                for (String header : headerMap.keySet()) {
                    if (!header.startsWith("T")) continue;
                    String hhmm = header.substring(1);
                    String dateStr = formatYmdTime(ymd, hhmm);
                    long ts = parseDateToTimestamp2(dateStr);
                    double val = parseDoubleOrZero(rec.get(header));
                    fhNode.put(String.valueOf(ts), val);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("解析 MXFH 文件失败", e);
        }

        // --- 4. 合成每个 busid 的 JSON ---
        List<String> results = new ArrayList<>();
        for (Map.Entry<Integer, ObjectNode> entry : busidToFhMap.entrySet()) {
            int busid = entry.getKey();
            ObjectNode fhData = entry.getValue();

            ObjectNode root = mapper.createObjectNode();
            ObjectNode inputData = root.putObject("input_data");
            inputData.put("busid", busid);

            ObjectNode content = inputData.putObject("content");
            content.set("qw", sharedContent.get("qw"));
            content.set("xdsd", sharedContent.get("xdsd"));
            content.set("jsl", sharedContent.get("jsl"));
            content.set("fh", fhData);

            results.add(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root));
        }
        System.out.println(results);
        return results;
    }

    /**
     * 解析字符串为 double，不可用时返回 0
     */
    private double parseDoubleOrZero(String s) {
        if (StringUtils.isBlank(s)) return 0.0;
        try {
            return Double.parseDouble(s);
        } catch (NumberFormatException e) {
            return 0.0;
        }
    }

    /**
     * 将 YMD（如 "20100508"）和 HHmm （如 "1130"）组合成 "yyyy/MM/dd HH:mm"。
     *
     * @param ymd  八位日期字符串
     * @param hhmm 四位时间字符串
     */
    private String formatYmdTime(String ymd, String hhmm) {
        // 假设 ymd 长度=8, hhmm 长度=4
        return ymd.substring(0, 4) + "/" +
                ymd.substring(4, 6) + "/" +
                ymd.substring(6, 8) + " " +
                hhmm.substring(0, 2) + ":" +
                hhmm.substring(2, 4);
    }

    // 解析日期字符串为时间戳
    public static long parseDateToTimestamp(String dateStr) throws ParseException {
        if (dateStr.contains("-")) {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            Date date = dateFormat.parse(dateStr);
            return date.getTime();
        } else {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
            Date date = dateFormat.parse(dateStr);
            return date.getTime();
        }
    }

    public static long parseDateToTimestamp2(String dateStr) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
        Date date = dateFormat.parse(dateStr);
        return date.getTime();
    }

}